package com.ck567.netty.chatroom.protocol

import com.google.gson.*
import java.io.*
import java.lang.reflect.Type
import java.nio.charset.StandardCharsets

interface Serializer {
    // 反序列化方法
    fun <T> deserialize(clazz: Class<T>?, bytes: ByteArray?): T

    // 序列化方法
    fun <T> serialize(`object`: T): ByteArray

    enum class Algorithm : Serializer {
        Java {
            override fun <T> deserialize(clazz: Class<T>?, bytes: ByteArray?): T {
                return try {
                    val ois = ObjectInputStream(ByteArrayInputStream(bytes))
                    ois.readObject() as T
                } catch (e: IOException) {
                    throw RuntimeException("反序列化失败", e)
                } catch (e: ClassNotFoundException) {
                    throw RuntimeException("反序列化失败", e)
                }
            }

            override fun <T> serialize(`object`: T): ByteArray {
                return try {
                    val bos = ByteArrayOutputStream()
                    val oos = ObjectOutputStream(bos)
                    oos.writeObject(`object`)
                    bos.toByteArray()
                } catch (e: IOException) {
                    throw RuntimeException("序列化失败", e)
                }
            }
        },
        Json {
            override fun <T> deserialize(clazz: Class<T>?, bytes: ByteArray?): T {
                val gson = GsonBuilder().registerTypeAdapter(Class::class.java, ClassCodec()).create()
                val json = String(bytes!!, StandardCharsets.UTF_8)
                return gson.fromJson(json, clazz)
            }

            override fun <T> serialize(`object`: T): ByteArray {
                val gson = GsonBuilder().registerTypeAdapter(Class::class.java, ClassCodec()).create()
                val json = gson.toJson(`object`)
                return json.toByteArray(StandardCharsets.UTF_8)
            }
        }
    }

    class ClassCodec : JsonSerializer<Class<*>>,
        JsonDeserializer<Class<*>> {
        @Throws(JsonParseException::class)
        override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Class<*> {
            return try {
                val str = json.asString
                Class.forName(str)
            } catch (e: ClassNotFoundException) {
                throw JsonParseException(e)
            }
        }

        //   String.class
        override fun serialize(src: Class<*>, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
            // class -> json
            return JsonPrimitive(src.name)
        }
    }
}